package io.xccit.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import io.xccit.realm.CustomLoginRealm;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author CH_ywx
 * @Date 2023-06-01
 * @Description Shiro配置类
 */
@Configuration
public class ShiroConfig {
    @Autowired
    private CustomLoginRealm loginRealm;

    /**
     * @return 默认的web安全管理器
     */
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        //创建安全管理器对象
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //创建加密对象
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //设置加密对象的加密方式和迭代次数
        matcher.setHashAlgorithmName("MD5");
        matcher.setHashIterations(3);
        //给自定义的realm设置加密对象
        loginRealm.setCredentialsMatcher(matcher);
        /*
         * 多个Realm代码实现
         */
        ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        defaultWebSecurityManager.setAuthenticator(modularRealmAuthenticator);
        //创建Realm集合
        List<Realm> realms = new ArrayList<>();
        realms.add(loginRealm);
        //设置安全管理器的realm
//        defaultWebSecurityManager.setRealm(loginRealm);
        defaultWebSecurityManager.setRealms(realms);
        //设置rememberMe
        defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
        //设置缓存管理器
        defaultWebSecurityManager.setCacheManager(getEhCacheManager());
        return defaultWebSecurityManager;
    }

    /**
     * @return 缓存管理器
     */
    public EhCacheManager getEhCacheManager(){
        //设置缓存管理器
        EhCacheManager ehCacheManager = new EhCacheManager();
        InputStream inputStreamForPath = null;
        try {
            inputStreamForPath = ResourceUtils.getInputStreamForPath("classpath:ehcache/ehcache-shiro.xml");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        CacheManager cacheManager = new CacheManager(inputStreamForPath);
        ehCacheManager.setCacheManager(cacheManager);
        return ehCacheManager;
    }
    //cookie属性设置
    public SimpleCookie rememberMeCookie() {
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        //设置跨域
        //cookie.setDomain(domain);
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(30 * 24 * 60 * 60);//30天免登录
        return cookie;
    }

    //创建Shiro的cookie管理对象
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //注意：cookieRememberMeManager.setCipherKey传入参数为长度16位的byte[]，否则会报Unable to init cipher instance:无法初始化密码实例的错误
        cookieRememberMeManager.setCipherKey("1234567890987654".getBytes());
        return cookieRememberMeManager;
    }

    @Bean
    public DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
        //设置不认证可以访问的资源
        definition.addPathDefinition("/user/login", "anon");//资源路径  不认证可访问标志
        definition.addPathDefinition("/login", "anon");
        //将用户登录校验放入未登录可访问资源
        definition.addPathDefinition("/user/loginverify", "anon");
        //配置登出过滤器
        definition.addPathDefinition("/logout", "logout");
        //设置必须认证才可访问的资源
        definition.addPathDefinition("/**", "authc");//资源路径  认证才可访问标志
        //添加存在用户的过滤器（rememberMe）
        definition.addPathDefinition("/**", "user");
        return definition;
    }

    /**
     * 配置Shiro前端标签解析器
     * @return 前端标签解析器
     */
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }
}
